import json
import sys
import time

import requests
import base64
import hmac
import hashlib
import uuid
from urllib.parse import urlencode,quote


class Feishu():
    def __init__(self):
        self.app_id = 'cli_a756a1fe763b900d'
        capp_secret = '0sAjAbRKBj9FNUMXcdUMyd11xJVgb1BG'

    def get_access_token(self):
        url = "https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal/"
        data = {
            "app_id": self.app_id,
            "app_secret": self.app_idapp_secret
        }
        response = requests.post(url, data=data)
        response_data = response.json()
        return response_data.get('app_access_token')

    def write_to_doc(self, access_token, doc_id, content):
        url = f"https://open.feishu.cn/open-apis/doc/v3/docs/{doc_id}"
        headers = {
            "Authorization": f"Bearer {access_token}",
            "Content-Type": "application/json"
        }
        data = {
            "content": content  # 这里的content需要是符合飞书文档格式的JSON结构，例如：{"text": "这是要写入的内容"}
        }
        response = requests.post(url, headers=headers, json=data)
        return response.json()

    def run(self):
        app_id = 'your_app_id'
        app_secret = 'your_app_secret'
        doc_id = 'your_doc_id'  # 确保这是正确的文档ID
        content = '{"text": "这是要写入的内容"}'  # 示例内容，根据实际需求调整格式和内容

        access_token = self.get_access_token()
        result = self.write_to_doc(access_token, doc_id, content)
        print(result)

class XiMaLaYa():
    def __init__(self):
        # https://open.ximalaya.com/doc/detailApi?categoryId=10&articleId=56#%E6%8E%A5%E5%85%A5%E6%8C%87%E5%AF%BC
        # 喜马拉雅开放平台应用公钥
        self.app_key = 'fd43e73dc45f864a69e62f84ec14d6a9'
        #
        self.secret_key = '508354c289c6d2b45ea47352e18dd012'
        # self.server_auth_static_key = "XEbin4wC"
        """
        1-IOS端，2- Android端，3-Web端，4-API_OR_LINUX，5-ECOS，6-小程序，7-智能音箱，8-H5子站
        【接入方式为API的合作方】请注意：
        1. 如果是从客户端发起API接口调用或者通过客户端发起但通过服务端中转调用API接口，则传：1-iOS端，2-Android端，3-H5或PC Web端，请严格按实际情况回传，否则审核上线可能不通过；
        2. 如果是纯粹从服务端发起调用（常见于内容数据同步场景），则传：4-纯服务端API调用；
        3. 对于支付API相关接口有client_os_type参数，只能传：1-iOS端，2-Android端，请根据实际情况设置，否则会影响正常支付流程请严格按实际情况回传，否则审核上线可能不通过；
        """
        self.client_os_type = 4
        self.nonce = uuid.uuid4().hex  # 一个随机字符串，随机性越大越好，每个请求都需要重新生成
        self.timestamp = int(
            time.time() * 1000)  # 当前Unix毫秒数时间戳，每个请求都需要重新生成，与当前时间间隔不要超过一小时，注意：对于分销接口的timestamp参数，与当前时间间隔不要超过5分钟
        self.device_id = self.generate_device_id()  # 设备唯一标识，根据终端类型（Android、iOS、Linux、Web等）不一样生成规则不一样，请参考设备ID生成说明
        self.device_id_type = 'UUID'  # device_id设备唯一标识字段类型，主要有以下六种设备标识类型：OAID、OAID_MD5、Android_ID、Android_ID_MD5、IDFA、 IDFA_MD5、UUID，请参考设备ID生成算法
        self.server_api_version = '1.0.0'  # api版本号，目前为： 1.0.0。
        self.sig = ''  # 签名参数，对除sig外所有参数进行签名计算得到的值。每次请求都要重新生成，不可复用，sig参数全为小写。请参考 签名生成算法。
        self.baseUrl = 'https://api.ximalaya.com'

        self.post_data = self.generate_post_data()

    def generate_post_data(self):

        post_data = {
            "app_key": self.app_key,
            "client_os_type": self.client_os_type,
            "nonce": uuid.uuid4().hex,
            "timestamp": int(time.time() * 1000),
            "server_api_version": self.server_api_version,
            "device_id": self.device_id,
            "device_id_type": self.device_id_type
        }
        return post_data

    def generate_device_id(self):
        """
        设备ID生成算法
        :return:
        """
        # device_id = str(uuid.uuid4())
        # print(device_id)
        device_id = "7a0472a6-5c87-4a86-a8cf-50525751aefa"
        return device_id

    def calculate_signature(self, params, seed):
        """
        计算 API 请求签名（键值对字典版）
        :param params: 参数字典（包含所有请求参数，自动过滤sig）
        :param seed: 加密种子 = app_secret + server_static_key
        :return: 签名字符串
        """
        if not params or not seed:
            raise ValueError("参数和加密种子不能为空")

        # 过滤sig参数并创建参数副本
        filtered_params = {k: v for k, v in params.items() if k != 'sig'}

        # 参数排序与拼接
        sorted_params = sorted(filtered_params.items(), key=lambda x: x[0])
        query_str = '&'.join([f"{k}={v}" for k, v in sorted_params])

        # Base64编码
        base64_encoded = base64.b64encode(query_str.encode('utf-8')).decode('utf-8')

        # HMAC-SHA1计算
        hmac_sha1 = hmac.new(
            seed.encode('utf-8'),
            base64_encoded.encode('utf-8'),
            hashlib.sha1
        )

        hmac_sha1 = hmac_sha1.digest()

        # 步骤6：MD5生成最终签名
        md5 = hashlib.md5()
        md5.update(hmac_sha1)
        signature = md5.hexdigest()

        uri = '&'.join([f'{k}={v}' for k, v in params.items()]) + '&sig=' + signature
        return uri

    def request_data(self, url, method='GET', params=None, data=None):
        if method == 'POST':
            response = requests.post(url, params=params, data=data)
        else:
            response = requests.get(url, params=params)
        if response.status_code == 200:
            return response.json()
        return response.json()

    def get_recommend_albums(self):
        """
        每日推荐专辑
        desc: https://open.ximalaya.com/doc/detailApi?categoryId=10&articleId=56#%E6%AF%8F%E6%97%A5%E6%8E%A8%E8%8D%90%E4%B8%93%E8%BE%91
        :return:
        """
        params = self.post_data
        params["page"] = 1
        params["count"] = 20

        uri = self.calculate_signature(params, self.secret_key)

        print("uri: ", uri)

        # url = "https://api.ximalaya.com/operation/recommend_albums?app_key=b617866c20482d133d5de66fceb37da3&client_os_type=4&nonce=mumimgduq0n×tamp=1575366140035&server_api_version=1.0.0&device_id=32cc6f279c7a11e9a26e0235d2b38928&page=1&count=20&sig=0898a649a5a3e9fd73bc43333e12b982"
        url = "https://api.ximalaya.com/operation/recommend_albums?" + uri
        response = requests.get(url)
        print(response.status_code)
        print(response.json())

    def get_free_category(self):
        """
        分类列表
        desc: https://open.ximalaya.com/doc/detailApi?categoryId=10&articleId=6#%E5%88%86%E7%B1%BB%E5%88%97%E8%A1%A8
        :return:
        """
        params = self.post_data
        uri = self.calculate_signature(params, self.secret_key)
        # url = "https://api.ximalaya.com/categories/list?app_key=b617866c20482d133d5de66fceb37da3&client_os_type=4&nonce=qoho97zuh8×tamp=1699518964853&server_api_version=1.0.0&device_id=32cc6f279c7a11e9a26e0235d2b38928&device_id_type=OAID&sig=815ac2f5f6661a9266eefd79e1d49e3a"
        url = "https://api.ximalaya.com/categories/list?" + uri
        print(url)
        categories = self.request_data(url)
        category_dict = {row['id']: row['category_name'] for row in categories}
        for row in categories:
            print({row['id']: row['category_name']})


    def get_hot_words(self):
        """
        获取热搜词
        :return:
        """
        params = self.post_data
        params['top'] = 20
        uri = self.calculate_signature(params, self.secret_key)

        url = "https://api.ximalaya.com/search/hot_words?{}".format(uri)
        # url = "https://api.ximalaya.com/search/hot_words?app_key=b617866c20482d133d5de66fceb37da3&client_os_type=4&nonce=3503b52fe92bf1abbe7ff8d82f7dec69&server_api_version=1.0.0&top=20&sig=ad2b1dd9bcfa793e60940f9d8b40e7e6"
        result = self.request_data(url)
        print(result)

    def operation_category(self):
        """
        运营分类列表
        :return:
        """
        params = self.post_data
        uri = self.calculate_signature(params, self.secret_key)
        # url = "https://api.ximalaya.com/operation/categories?app_key=b617866c20482d133d5de66fceb37da3&client_os_type=4&nonce=h8pzhj7m15n×tamp=1584694832952&server_api_versionn=1.0.0&device_id=32cc6f279c7a11e9a26e0235d2b38928&sig=c32c621d29d2bb74b7cd8fd3103fa43f"
        url = "https://api.ximalaya.com/operation/categories?" + uri
        result = self.request_data(url)
        print(result)

    def get_search_albums(self, keyword):
        """
        多筛选条件搜索专辑---根据关键词搜索喜马拉雅音频专辑
        desc:https://open.ximalaya.com/doc/detailApi?categoryId=10&articleId=26#%E5%A4%9A%E7%AD%9B%E9%80%89%E6%9D%A1%E4%BB%B6%E6%90%9C%E7%B4%A2%E4%B8%93%E8%BE%91
        :param keyword: 关键词
        :return:
        """
        params = self.post_data

        params['title'] = keyword
        params['is_paid'] = 0 #是否付费 1-付费 0-免费
        # params['sort_by'] = 'play_count' #排序字段，可选值：created_at、updated_at、discountedPrice、play_count、week_score_plus
        # params['desc'] = True #true-降序排列（喜马拉雅正序） false-升序排列（喜马拉雅倒序）
        params['page'] = 1
        params['count'] = 10
        uri = self.calculate_signature(params, self.secret_key)

        # url="https://api.ximalaya.com/v2/search/albums?app_key=b617866c20482d133d5de66fceb37da3&client_os_type=4&nonce=2a34df476c75497fc4cb2a518733c85b&server_api_version=1.0.0&title=%E5%A5%BD%E5%A5%BD%E8%AF%B4%E8%AF%9D&page=1&count=30&sig=890eca159687fff35f79c591628741e5"
        url = "https://api.ximalaya.com/v2/search/albums?" + uri

        result = self.request_data(url)
        print(result.keys())
        total_page = result['total_page']  # 总共多少页
        total_count = result['total_count']  # 总记录数
        current_page = result['current_page']  # 当前页码

        for row in result["albums"]:
            # print(json.dumps(row, indent=4, ensure_ascii=False))
            temp_dict = {
                "album_id": str(row['id']),
                "album_title": str(row['album_title']),
                "album_intro": row['album_intro'],
                "cover_url": row['cover_url'],
                "nickname": row['announcer']['nickname'],
                "announcer_id": row['announcer']['id'],
                "play_count": row['play_count'],
                "subscribe_count": row['subscribe_count'],
                "is_paid": row['is_paid'],
                "updated_at": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(row['updated_at']/1000)),
                "short_intro": row['short_intro'],
                "url": "https://www.ximalaya.com/album/" + str(row['id']),
            }
            # url: "https://www.ximalaya.com/album/57113169"


            # chinese_chars = ['专辑ID', '专辑标题', '专辑简介', '专辑封面原图', '用户昵称', '用户ID', '专辑被播放总次数',
            #                  '该专辑被订阅总次数', '是否付费', '更新时间', '专辑一句话简介', '专辑链接']
            # temp_dict = {char: str(value) for char, value in zip(chinese_chars, temp_dict.values())}

            print(temp_dict)


        print({"total_page": total_page, "total_count": total_count, "current_page": current_page})

    def get_search_tracks(self, keyword):
        """
        多筛选条件搜索声音
        :param keyword: 关键词
        :return:
        """
        params = self.post_data

        params['title'] = keyword
        params['page'] = 1
        params['count'] = 2
        uri = self.calculate_signature(params, self.secret_key)

        url = "https://api.ximalaya.com/v2/search/tracks?" + uri
        result = self.request_data(url)


        for row in result["tracks"]:
            # print(json.dumps(row, ensure_ascii=False, indent=4))
            temp_dict = {
                "id": row['id'],
                "kind": row['kind'],
                "category_id": row['category_id'],
                "nickname": row['announcer']['nickname'],
                "is_paid": row['is_paid'],
                "is_free": row['is_free'],
                "track_title": row['track_title'],
                "cover_url_large": row['cover_url_large'],
                "comment_count": row['comment_count'],
                "updated_at": row['updated_at'],
                # "updated_at": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(row['updated_at'])),
                "audio_url": "https://www.ximalaya.com/m-revision/page/track/queryRelativeTracksById?trackId={trackId}&preOffset=1&nextOffset=8&countKeys=play&order=2".format(
                    trackId=row['id']),
            }
            print(temp_dict)




    def get_track_video(self, msg):
        """
        获取视频播放地址
        :param msg:
        :return:
        """
        params = self.generate_post_data()
        params['track_id'] = msg['id']
        print(params)
        uri = self.calculate_signature(params, self.secret_key)
        # "https://mpay.ximalaya.com/open_pay/get_video_play_info?app_key=b617866c20482d133d5de66fceb37da3&third_uid=9901&timestamp=1541066839000&client_os_type=2&nonce=0103f3c7d20d31106cb15e99da82ad46&track_id=102930565&server_api_version=1.0.0&sig=36905beec006633078489b95c1228b8d"
        url = "https://mpay.ximalaya.com/open_pay/get_video_play_info?" + uri
        result = self.request_data(url)
        print(result)

    def get_last_play_tracks(self, msg):
        """
        获取某条声音在专辑内所属声音页信息列表
        :param msg:
        :return:
        """
        """https://api.ximalaya.com/tracks/get_last_play_tracks?app_key=b617866c20482d133d5de66fceb37da3&client_os_type=4&nonce=f7c76e474d52207e1f46f405c2cfeeea&server_api_version=1.0.0&album_id=10290336&track_id=49991897&count=5&sort=time_asc&sig=fc6780a69c0dbc6b3d1253132195c283"""

    def get_tracks_single(self, msg):
        """获取单个声音信息"""
        params = self.generate_post_data()
        params['track_id'] = msg['id']

        uri = self.calculate_signature(params, self.secret_key)
        url = "https://api.ximalaya.com/tracks/get_single?app_key=b617866c20482d133d5de66fceb37da3&client_os_type=4&nonce=7y890dtfsn3erj×tamp=1587634499026&server_api_version=1.0.0&device_id=32cc6f279c7a11e9a26e0235d2b38928&track_id=125686714&sig=9427e7c0496425343635e79c224387e8"
        url = "https://api.ximalaya.com/tracks/get_single?" + uri
        result = self.request_data(url)
        print(json.dumps(result, indent=4, ensure_ascii=False))


def xmly(keyword):
    """"""
    """
    {core: all
kw: 民间故事
spellchecker: true
device: iPhone
live: true}
"""
    headers = {
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36",
        "content-type": "application/x-www-form-urlencoded;charset=UTF-8",
        "cookie": "HWWAFSESID=e4ee8b80714516d43f; HWWAFSESTIME=1742471028902; _xmLog=h5&f5ce6e79-1f2a-408c-8f37-6c485afbb4bf&process.env.sdkVersion; wfp=ACNmOTg5M2RjYTk2OTY5OTBm-lXMhF2d5JR4bXdlYl93d3c; DATE=1742471027745; crystal=U2FsdGVkX1+qN+KSOoGAOadnZTDcxJxGIPxftTiKT6FrcGod2I85ABFU4GOCohxiKjBWRCCHcz2eBoS8KH9Q/r3TYdUfaUHA3n1fEspGKpw3aYvT8TGL+k3EvJ7+ZBn4AhPWkXtgrkGEK52Bqt94dxINGnFubqz6gicfnWUgNCrcdhKbueDutWpuH6IrKxCFeMbCalgDbf9GW1Z6lX04J47dFnciOuu26MTnltVpLuZFiRkOI58AhS9TWr2lNxvm; Hm_lvt_4a7d8ec50cfd6af753c4f8aee3425070=1742471029; HMACCOUNT=08EF1318578EE1AB; trackType=web; x_xmly_traffic=utm_source%3A%26utm_medium%3A%26utm_campaign%3A%26utm_content%3A%26utm_term%3A%26utm_from%3A; 1&remember_me=y; 1&_token=204431119&86D2CD30140N3DDE7F7250B644CEBF7D2B5DEADEF70125BF783775B66D1ADA6E1EDC69D7554838MF2AEF97CD372AFD_; 1_l_flag=204431119&86D2CD30140N3DDE7F7250B644CEBF7D2B5DEADEF70125BF783775B66D1ADA6E1EDC69D7554838MF2AEF97CD372AFD__2025-03-2019:44:21; impl=www.ximalaya.com.login; xm-page-viewid=ximalaya-web; assva6=U2FsdGVkX18wHpY+pvQ+dAg7+hlCLFxr06v2QYVK5X8=; assva5=U2FsdGVkX19Ubx2RZufqSFiswEeS8d36hBlt89s6mZKyH21+2VqBlhnwG2500azWudhC6Mtl7B0e8muny9jcNg==; Hm_lpvt_4a7d8ec50cfd6af753c4f8aee3425070=1742471850; web_login=1742471850431; cmci9xde=U2FsdGVkX1+V0pl6mvJlXSqy5kVv6wNFBKmd6YZ+USUPD2oa0IWqc4Ggt4Yvkki1YiqMDO3Zt376JtTwFUTIaw==; pmck9xge=U2FsdGVkX18/IkyxNPNl3yAoFeUUKDBhsl89Mv8bQ6k=; vmce9xdq=U2FsdGVkX1+SNDi3PvaOwqWTXe3ujuDgMGiHTFATavOHcHaRYxqv7sxO6Zc94JKck7x/fs1kTOi1av9x54d3FLzSjK8LL4dbU4uYc9rdupW/jbCdzh01ubQz1vx27vNWZ3tBECrFyVX8+r6v63a4NxfmQr3ZdxLL0KsoI3NbUzQ=",
        "referer": "https://www.ximalaya.com/so/" + quote(keyword),
        "xm-sign":"D2fk2fsuNMhY9jOBW+fHOncpVMDy/GNd072FNwhTw6lpEXaf&&OpHPti96R1AWae_oA9eBTgqQCYmVs8NO9ep_6wrPu5I_1",
    }
    print()
    url = "https://www.ximalaya.com/revision/search/main?core=all&kw={}&spellchecker=true&device=iPhone&live=true".format(quote(keyword))
    print(url)
    response = requests.get(url, headers=headers)
    if response.status_code == 200:
        result = response.json()
        print(result)
        print(result.keys())
        if 'album' not in result['data']:
            print("请求出错：%s" % result)
            sys.exit()
        album_list = result['data']['album']['docs']
        for row in album_list:
            print(row)
            print()



def main():

    time1 =time.time()
    ximalaya = XiMaLaYa()
    # 分类列表
    # ximalaya.get_free_category()

    # 每日推荐专辑
    # ximalaya.get_recommend_albums()

    # 运营分类列表
    # ximalaya.operation_category()

    # 获取单个声音信息

    # 获取热搜词
    # ximalaya.get_hot_words()

    # 多筛选条件搜索专辑---根据关键词搜索喜马拉雅音频专辑
    ximalaya.get_search_albums(keyword="民间故事")

    # 多筛选条件搜索声音-- 根据关键词搜索单个音频，包括小说故事、相声评书、京剧戏曲、新闻广播等
    # ximalaya.get_search_tracks(keyword="三国演义")
    used_time = time.time() -time1
    print("总耗时: ", used_time)


if __name__ == '__main__':
    # keyword = input("请输入你想查询的关键词: ")
    # if not keyword:
    #     print("您没输入任何内容")
    # resp = request_data(keyword)
    # print(resp)
    keyword= "民间故事"
    # xmly(keyword)
    main()

